using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using GraphProcessor;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Framework.Serialization;
using IQIGame.Onigao.Logic;
using IQIGame.Onigao.ToolApp;
using UnityEditor;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay.Editors
{
    public partial class LevelServiceBlackboard : Singleton<LevelServiceBlackboard>
    {
        private LevelServiceEditorCache mEditorCache;

        public LevelServiceEditorCache editorCache
        {
            get
            {
                if (this.mEditorCache == null)
                {
                    var rPath = Path.Combine(ConfigFileDicPath, "LevelServiceEditorCache.asset");
                    var rCache = AssetDatabase.LoadAssetAtPath<LevelServiceEditorCache>(rPath);
                    if (rCache == null)
                    {
                        rCache = ScriptableObject.CreateInstance<LevelServiceEditorCache>();
                        AssetDatabase.CreateAsset(rCache, rPath);
                    }
                    this.mEditorCache = rCache;
                }
                return this.mEditorCache;
            }
        }

        private const string BaseDirPath = "Assets/EditorConfig/LevelConfig/LevelService";
        private const string ConfigFileDicPath = "Assets/EditorConfig/LevelConfig/LevelServiceConfig";

        private LevelServiceBlackboard()
        {
        }

        private List<EditorLevelServiceConfig> configs = new List<EditorLevelServiceConfig>();

#region 导出

#region AddConfig

        public void AddService(EditorLevelServiceConfig serviceGroup)
        {
            this.configs.Add(serviceGroup);
        }

#endregion

        public void Clear()
        {
            this.configs.Clear();
            this.servicePrefab.Clear();
            this.exectuionPrefab.Clear();

            this.servicePrefabPathCache.Clear();
            this.executionPrefabPathCache.Clear();
            this.configCache.Clear();
            this.exectuionGroupCache.Clear();

            this.syncTempNode = null;
        }

        public void PackageAll()
        {
            // var rSelect = Selection.activeObject;
            // var rTargetDir = string.Empty;
            // if (rSelect != null)
            // {
            //     string path = AssetDatabase.GetAssetPath(rSelect);
            //     if (!string.IsNullOrEmpty(path))
            //     {
            //         var rDirFull = Path.GetFullPath(directoryPath);
            //         var rPathFull = Path.GetFullPath(path);
            //         if (rPathFull.StartsWith(rDirFull))
            //         {
            //             if (!Directory.Exists(path))
            //             {
            //                 path = Path.GetDirectoryName(path);
            //             }
            //
            //             rTargetDir = Path.GetFileName(path);
            //         }
            //     }
            // }
            // 强行指定全量
            var rTargetDir = "";
            if (string.IsNullOrEmpty(rTargetDir))
            {
                if (Directory.Exists(ConfigFileDicPath))
                {
                    Directory.Delete(ConfigFileDicPath, true);
                }
                Directory.CreateDirectory(ConfigFileDicPath);
                AssetDatabase.Refresh();
            }
            var rPackages = new List<string>();
            // 全量导入
            LevelServiceBlackboard.Instance.Clear();
            // 清理检查预设用记录
            this.packageServiceUnitPrefabKey.Clear();
            this.packageExecutionPrefabKey.Clear();

            var rDir = Directory.GetDirectories(BaseDirPath);
            for (int i = 0; i < rDir.Length; i++)
            {
                var rPath = rDir[i];
                if (!string.IsNullOrEmpty(rTargetDir) && Path.GetFileName(rPath) != rTargetDir)
                {
                    continue;
                }

                var rFiles = Directory.GetFiles(rPath);

                for (int j = 0; j < rFiles.Length; j++)
                {
                    if (rFiles[j].Contains(".meta"))
                    {
                        continue;
                    }
                    rFiles[j] = rFiles[j].Replace("\\", "/");
                    var graph = AssetDatabase.LoadAssetAtPath<BaseGraph>(rFiles[j]);
                    if (graph != null)
                    {
                        var rSortList = graph.nodes.OrderBy(n => n.computeOrder).ToList();
                        for (int k = 0; k < rSortList.Count; k++)
                        {
                            var rNode = rSortList[k];
                            rNode.OnProcess();
                        }
                        rPackages.Add(rFiles[j]);
                        this.Package(rFiles[j], false);
                    }
                    EditorUtility.SetDirty(graph);
                }
            }

            LogGame.Log("关卡服务全部导出完成");
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();

            // 全量导出单独检查预设
            this.CheckServicePrefabConfig();
            
            // 刷一下配置中间表记录所有的GUID
            this.SaveAllServiceGUIDToCsv();
        }

        public void Package(string graphPath, bool refresh = true)
        {
            var rEditorCache = this.editorCache;
            var rPathKey = graphPath.Replace(BaseDirPath, "");
            // asset文件路径对应的groupID
            if (!rEditorCache.allPathToService.TryGetValue(rPathKey, out var rCurList))
            {
                rCurList = new List<int>();
                rEditorCache.allPathToService[rPathKey] = rCurList;
            }
            rEditorCache.allPathToService[rPathKey] = this.configs.Select((x) => x.id).ToList();

            var rPath = this.GetBytesPathByAssetPath(graphPath);
            var rDirPath = Path.GetDirectoryName(rPath);
            if (!Directory.Exists(rDirPath))
            {
                Directory.CreateDirectory(rDirPath);
            }
            if (this.configs?.Count > 0)
            {
                this.configs.RemoveAll((x) => x.serviceUnits?.Count <= 0);
                var rBuf = new ByteBuf();
                SerializeByteBufUtil.SerializeList(rBuf, this.configs);
                File.WriteAllBytes(rPath, rBuf.Bytes);
            }

            if (this.servicePrefab.Count > 0 || this.exectuionPrefab.Count > 0)
            {
                this.ExportPrefab(graphPath, false);
            }

#region 反序列化测试 需要使用时打开注释

            // var rBuf2 = new ByteBuf(rBuf.Bytes);
            // var rList = new List<EditorLevelServiceConfig>();
            // SerializeByteBufUtil.DeSerializeList(rBuf2, ref rList);s

#endregion

            // 记录使用的预设
            for (int i = 0; i < this.configs.Count; i++)
            {
                this.GetServicePrefabKey(graphPath, this.configs[i]);
            }
            LogGame.Log($"关卡服务【{graphPath}】导出完成");
            this.SaveEditorCache();
            this.Clear();

            if (refresh)
            {
                // 检查预设
                this.CheckServicePrefabConfig();

                this.configCache.Clear();
                // 单体导出时候强制保存一下
                var rGraph = AssetDatabase.LoadAssetAtPath<BaseGraph>(graphPath);
                EditorUtility.SetDirty(rGraph);
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
                
                // 刷一下配置中间表记录所有的GUID
                this.SaveAllServiceGUIDToCsv();
            }
        }

#endregion

        private Dictionary<string, List<string>> packageServiceUnitPrefabKey = new Dictionary<string, List<string>>();
        private Dictionary<string, List<string>> packageExecutionPrefabKey = new Dictionary<string, List<string>>();

        private void GetServicePrefabKey(string graphPath, EditorLevelServiceConfig service)
        {
            if (!this.packageServiceUnitPrefabKey.TryGetValue(graphPath, out var rList))
            {
                rList = new List<string>();
                this.packageServiceUnitPrefabKey[graphPath] = rList;
            }
            if (!this.packageExecutionPrefabKey.TryGetValue(graphPath, out var rList2))
            {
                rList2 = new List<string>();
                this.packageExecutionPrefabKey[graphPath] = rList2;
            }
            foreach (var rServiceUnit in service.serviceUnits)
            {
                if (!string.IsNullOrEmpty(rServiceUnit.prefabKey))
                {
                    rList.Add(rServiceUnit.prefabKey);
                }
                else
                {
                    var rExList = new List<EditorLevelServiceExecutionConfig>();
                    rExList.AddRange(rServiceUnit.execution);
                    rExList.AddRange(rServiceUnit.preExecution);
                    rExList.AddRange(rServiceUnit.vetoExecution);
                    foreach (var rExecutionConfig in rExList)
                    {
                        if (rExecutionConfig.executionType == (int)ServiceExecutionType.Prefab &&
                            rExecutionConfig.customConfig is LevelServiceExecutionCustom_Prefab rPrefabEx &&
                            !string.IsNullOrEmpty(rPrefabEx.key))
                        {
                            rList2.Add(rPrefabEx.key);
                        }
                    }
                }
            }
        }

        private void CheckServicePrefabConfig()
        {
            LevelServiceEditorConfigFactory.ClearPrefabCache();
            foreach (var rPair in this.packageServiceUnitPrefabKey)
            {
                for (int i = 0; i < rPair.Value.Count; i++)
                {
                    var rKey = rPair.Value[i];
                    var rPrefab = LevelServiceEditorConfigFactory.GetServiceUnitPrefab(rKey);
                    if (rPrefab == null)
                    {
                        LogGame.LogError($"文件【{rPair.Key}】中，服务单元预设【{rKey}】不存在，请检查预设是否丢失");
                    }
                }
            }

            foreach (var rPair in this.packageExecutionPrefabKey)
            {
                for (int i = 0; i < rPair.Value.Count; i++)
                {
                    var rKey = rPair.Value[i];
                    var rPrefab = LevelServiceEditorConfigFactory.GetExecutionPrefab(rKey);
                    if (rPrefab == null)
                    {
                        LogGame.LogError($"文件【{rPair.Key}】中，执行预设【{rKey}】不存在，请检查预设是否丢失");
                    }
                }
            }
            this.packageServiceUnitPrefabKey.Clear();
            this.packageExecutionPrefabKey.Clear();
        }

        private string GetBytesPathByAssetPath(string graphPath)
        {
            return Path.ChangeExtension(graphPath, ".bytes").Replace("/LevelService/", "/LevelServiceConfig/");
        }

        public List<BaseGraph> GetAllGraph(string targetDir = "")
        {
            var rDir = Directory.GetDirectories(BaseDirPath);
            List<BaseGraph> rAllGraph = new List<BaseGraph>();
            for (int i = 0; i < rDir.Length; i++)
            {
                var rPath = rDir[i];
                if (!string.IsNullOrEmpty(targetDir))
                {
                    var rCheckPath1 = rPath.Replace("\\", "").Replace("/", "");
                    var rCheckPath2 = targetDir.Replace("\\", "").Replace("/", "");
                    if (rCheckPath1 != rCheckPath2)
                    {
                        continue;
                    }
                }
                var rFiles = Directory.GetFiles(rPath);

                for (int j = 0; j < rFiles.Length; j++)
                {
                    if (rFiles[j].Contains(".meta"))
                    {
                        continue;
                    }
                    rFiles[j] = rFiles[j].Replace("\\", "/");
                    var graph = AssetDatabase.LoadAssetAtPath<BaseGraph>(rFiles[j]);
                    if (graph == null)
                    {
                        continue;
                    }
                    rAllGraph.Add(graph);
                }
            }
            return rAllGraph;
        }

        private Dictionary<EditorLevelServiceConfig, string> GetAllConfig(string targetDir = "")
        {
            var rDir = Directory.GetDirectories(ConfigFileDicPath);
            var rCheckPath2 = targetDir.Replace("\\", "").Replace("/", "");
            Dictionary<EditorLevelServiceConfig, string> rAllConfig = new Dictionary<EditorLevelServiceConfig, string>();
            for (int i = 0; i < rDir.Length; i++)
            {
                var rPath = rDir[i];
                if (!string.IsNullOrEmpty(targetDir))
                {
                    var rCheckPath1 = rPath.Replace("\\", "").Replace("/", "");
                    if (rCheckPath1 != rCheckPath2)
                    {
                        continue;
                    }
                }
                var rFiles = Directory.GetFiles(rPath);

                for (int j = 0; j < rFiles.Length; j++)
                {
                    if (rFiles[j].Contains(".meta"))
                    {
                        continue;
                    }
                    rFiles[j] = rFiles[j].Replace("\\", "/");
                    var rFilePath = rFiles[j];
                    var rBytes = AssetDatabase.LoadAssetAtPath<TextAsset>(rFilePath).bytes;
                    if (rBytes == null)
                    {
                        continue;
                    }
                    var rBuf2 = new ByteBuf(rBytes);
                    var rList = rBuf2.DeSerializeList<EditorLevelServiceConfig>();
                    // SerializeByteBufUtil.DeSerializeList(rBuf2, ref rList);
                    for (int k = 0; k < rList.Count; k++)
                    {
                        rAllConfig.Add(rList[k], rFilePath);
                    }
                }
            }
            return rAllConfig;
        }
        
        private void SaveEditorCache()
        {
            if (this.editorCache != null)
            {
                EditorUtility.SetDirty(this.editorCache);
                AssetDatabase.SaveAssetIfDirty(this.editorCache);
            }
        }

        private void SaveAllServiceGUIDToCsv()
        {
            // 读CSV
            var rCsvPath = Path.Combine(Path.GetDirectoryName(Application.dataPath), "Tables/策划配置表/编辑器/关卡服务索引.csv");
            var rSb = new StringBuilder();
            using (StreamReader reader = new StreamReader(rCsvPath, EditorEncodingHelper.GB2312))
            {
                for (int i = 0; i < 5; i++)
                {
                    rSb.Append(reader.ReadLine());
                    rSb.Append("\r\n");
                }
            }
            var rAllConfig = this.GetAllConfig();
            int nConfigID = 0;
            foreach (var rPair in rAllConfig)
            {
                var rConfig = rPair.Key;
                var nGuid = rConfig.id;
                var rDesc = "";
                bool bHasChangeName = false;
                for (int j = 0; j < rConfig.serviceUnits.Count; j++)
                {
                    rDesc += $"[{rConfig.serviceUnits[j].name}]";
                    bHasChangeName |= rConfig.serviceUnits[j].name != "服务";
                }
                if (!bHasChangeName)
                {
                    rDesc = "";
                }
                var rDirName = Path.GetFileNameWithoutExtension(Path.GetDirectoryName(rPair.Value));
                var rPath = Path.GetFileNameWithoutExtension(rPair.Value);
                
                rSb.Append($"{++nConfigID},{nGuid},{rDirName}/{rPath}{rDesc}");
                rSb.Append("\r\n");
            }

            File.WriteAllText(rCsvPath, rSb.ToString(), EditorEncodingHelper.GB2312);
        }
    }
}